﻿namespace SsisLdapSource.DirectoryServicesProtocolsExtensions
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public partial class LdapMetaMapFactory
    {
        private readonly List<string> generilizedTimeAttributes = new List<string>
        {
             "1.3.6.1.4.1.1466.115.121.1.24"
        };

        private readonly List<string> utcGenerilizedTimeAttributes = new List<string>
        {
             "1.3.6.1.4.1.1466.115.121.1.53"
        };

        private bool DoesAttributeValueHasDifferentSemanticMeaning(string attributeName, string rfc2252Syntax)
        {
            return utcGenerilizedTimeAttributes.Contains(rfc2252Syntax) ||
                   generilizedTimeAttributes.Contains(rfc2252Syntax) ||
                   initializationValues.Int64DateTimeEncodedAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase) ||
                   initializationValues.GuidEncodedBinaryAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase) ||
                   initializationValues.StringEncodedIntAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase) ||
                   initializationValues.SidEncodedBinaryAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase);
        }

        private Type GetDotNetSemanticType(string attributeName, string rfc2252Syntax)
        {
            var typeBasedOnAttributeName = GetDotNetSemanticTypeBasedOnAttributeName(attributeName);
            if (typeBasedOnAttributeName != null)
            {
                return typeBasedOnAttributeName;
            }

            var typeBasedOnRFCSyntax = GetDotNetSemanticTypeBasedOnRFC2252Syntax(rfc2252Syntax);
            if (typeBasedOnRFCSyntax != null)
            {
                return typeBasedOnRFCSyntax;
            }

            throw new Exception(
                string.Format(
                "A combination of attributeName {0} and attributeSyntax {1} could not be resolved to a semantic .NET type",
                    attributeName,
                    rfc2252Syntax));
        }

        private DecodeLdapValue GetDotNetSemanticConverter(string attributeName, string rfc2252Syntax)
        {
            var converterBasedOnAttributeName = GetSemanticDecoderBasedOnAttributeName(attributeName);
            if (converterBasedOnAttributeName != null)
            {
                return converterBasedOnAttributeName;
            }

            var converterBasedOnRFCSyntax = GetSemanticDecoderBasedOnRFC2252Syntax(rfc2252Syntax);
            if (converterBasedOnRFCSyntax != null)
            {
                return converterBasedOnRFCSyntax;
            }

            throw new Exception(
                string.Format(
                "A combination of attributeName {0} and attributeSyntax {1} could not be resolved to a semantic .NET value converter",
                    attributeName,
                    rfc2252Syntax));
        }

        private Type GetDotNetSemanticTypeBasedOnRFC2252Syntax(string rfc2252Syntax)
        {
            if (utcGenerilizedTimeAttributes.Contains(rfc2252Syntax) || generilizedTimeAttributes.Contains(rfc2252Syntax))
            {
                return typeof(DateTime);
            }

            return null;
        }

        private Type GetDotNetSemanticTypeBasedOnAttributeName(string attributeName)
        {
            if (initializationValues.Int64DateTimeEncodedAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return typeof(DateTime);
            }

            if (initializationValues.GuidEncodedBinaryAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return typeof(Guid);
            }

            // Though it is possible to convert SID binary representation into SecurityIdentifier, sending this 
            // type through SSIS pipeline does not seem to work, since SSIS does not support this type
            if (initializationValues.SidEncodedBinaryAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return typeof(string);
            }

            if (initializationValues.StringEncodedIntAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return typeof(int);
            }

            return null;
        }

        private DecodeLdapValue GetSemanticDecoderBasedOnAttributeName(string attributeName)
        {
            if (initializationValues.Int64DateTimeEncodedAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return LdapValueDecoder.DecodeInt64EncodedTimeValue;
            }

            if (initializationValues.GuidEncodedBinaryAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return LdapValueDecoder.DecodeObjectGUIDValue;
            }

            if (initializationValues.SidEncodedBinaryAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return LdapValueDecoder.DecodeObjectSidValue;
            }

            if (initializationValues.StringEncodedIntAttributes.Contains(attributeName, StringComparer.OrdinalIgnoreCase))
            {
                return LdapValueDecoder.DecodeStringEncodedInt;
            }

            return null;
        }

        private DecodeLdapValue GetSemanticDecoderBasedOnRFC2252Syntax(string rfc2252Syntax)
        {
            if (generilizedTimeAttributes.Contains(rfc2252Syntax))
            {
                return LdapValueDecoder.DecodeGeneralizedTime;
            }

            if (utcGenerilizedTimeAttributes.Contains(rfc2252Syntax))
            {
                return LdapValueDecoder.DecodeUtcGeneralizedTime;
            }

            return null;
        }
    }
}
